don't create dangling pointers to the appearance attributes from the line
authorHavoc Pennington <hp@pobox.com>
Sat, 2 Dec 2000 07:51:37 +0000 (07:51 +0000)
committerHavoc Pennington <hp@src.gnome.org>
Sat, 2 Dec 2000 07:51:37 +0000 (07:51 +0000)
2000-11-30  Havoc Pennington  <hp@pobox.com>

* gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create
dangling pointers to the appearance attributes from the
line display

* gdk/gdkdraw.c (gdk_drawable_get_image): allow negative
width/height to mean "full width/height of drawable"

* gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple
click to select word/line

* gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters
when getting log attrs. Get a slice, so that pixmaps and stuff
are properly handled.

* gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you
paste into the selection (replaces selection now, previously
crashed or added to selection). Reveals longstanding btree bug -
select multiple lines, middle-click on the selection, boom. This
isn't related to my changes though.

* gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect
PangoLogAttrs changes
(gtk_entry_move_backward_word): ditto

        * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion
functions return bool whether the iter moved onto a
dereferenceable position.

 * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public
 functions for motion in terms of display lines.

 * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to
 get the buffer a mark is inside

19 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
gdk/gdkdraw.c
gtk/gtkentry.c
gtk/gtktextbuffer.c
gtk/gtktextdisplay.c
gtk/gtktextiter.c
gtk/gtktextiter.h
gtk/gtktextlayout.c
gtk/gtktextlayout.h
gtk/gtktextmark.c
gtk/gtktextmark.h
gtk/gtktextview.c
gtk/gtktextview.h

index 6f525e615236608b1fad29102288bf4185a6c7da..49b9f5c17a874f58b7e1a508e252b77b0c10e61d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,40 @@
-2000-12-01    <alexl@redhat.com>
+2000-11-30  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create
+       dangling pointers to the appearance attributes from the 
+       line display
+
+       * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative
+       width/height to mean "full width/height of drawable"
+
+       * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple
+       click to select word/line
+       
+       * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters 
+       when getting log attrs. Get a slice, so that pixmaps and stuff
+       are properly handled.
+
+       * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you
+       paste into the selection (replaces selection now, previously
+       crashed or added to selection). Reveals longstanding btree bug -
+       select multiple lines, middle-click on the selection, boom. This
+       isn't related to my changes though.
+
+       * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect
+       PangoLogAttrs changes
+       (gtk_entry_move_backward_word): ditto
+
+        * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion
+       functions return bool whether the iter moved onto a
+       dereferenceable position.
+       * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public
+       functions for motion in terms of display lines.
+
+       * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to
+       get the buffer a mark is inside
+       
+2000-12-01  Alexander Larsson  <alexl@redhat.com>
 
        * gdk/linux-fb/Makefile.am:
        * modules/linux-fb/Makefile.am:
index 6f525e615236608b1fad29102288bf4185a6c7da..49b9f5c17a874f58b7e1a508e252b77b0c10e61d 100644 (file)
@@ -1,4 +1,40 @@
-2000-12-01    <alexl@redhat.com>
+2000-11-30  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create
+       dangling pointers to the appearance attributes from the 
+       line display
+
+       * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative
+       width/height to mean "full width/height of drawable"
+
+       * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple
+       click to select word/line
+       
+       * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters 
+       when getting log attrs. Get a slice, so that pixmaps and stuff
+       are properly handled.
+
+       * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you
+       paste into the selection (replaces selection now, previously
+       crashed or added to selection). Reveals longstanding btree bug -
+       select multiple lines, middle-click on the selection, boom. This
+       isn't related to my changes though.
+
+       * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect
+       PangoLogAttrs changes
+       (gtk_entry_move_backward_word): ditto
+
+        * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion
+       functions return bool whether the iter moved onto a
+       dereferenceable position.
+       * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public
+       functions for motion in terms of display lines.
+
+       * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to
+       get the buffer a mark is inside
+       
+2000-12-01  Alexander Larsson  <alexl@redhat.com>
 
        * gdk/linux-fb/Makefile.am:
        * modules/linux-fb/Makefile.am:
index 6f525e615236608b1fad29102288bf4185a6c7da..49b9f5c17a874f58b7e1a508e252b77b0c10e61d 100644 (file)
@@ -1,4 +1,40 @@
-2000-12-01    <alexl@redhat.com>
+2000-11-30  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create
+       dangling pointers to the appearance attributes from the 
+       line display
+
+       * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative
+       width/height to mean "full width/height of drawable"
+
+       * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple
+       click to select word/line
+       
+       * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters 
+       when getting log attrs. Get a slice, so that pixmaps and stuff
+       are properly handled.
+
+       * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you
+       paste into the selection (replaces selection now, previously
+       crashed or added to selection). Reveals longstanding btree bug -
+       select multiple lines, middle-click on the selection, boom. This
+       isn't related to my changes though.
+
+       * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect
+       PangoLogAttrs changes
+       (gtk_entry_move_backward_word): ditto
+
+        * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion
+       functions return bool whether the iter moved onto a
+       dereferenceable position.
+       * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public
+       functions for motion in terms of display lines.
+
+       * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to
+       get the buffer a mark is inside
+       
+2000-12-01  Alexander Larsson  <alexl@redhat.com>
 
        * gdk/linux-fb/Makefile.am:
        * modules/linux-fb/Makefile.am:
index 6f525e615236608b1fad29102288bf4185a6c7da..49b9f5c17a874f58b7e1a508e252b77b0c10e61d 100644 (file)
@@ -1,4 +1,40 @@
-2000-12-01    <alexl@redhat.com>
+2000-11-30  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create
+       dangling pointers to the appearance attributes from the 
+       line display
+
+       * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative
+       width/height to mean "full width/height of drawable"
+
+       * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple
+       click to select word/line
+       
+       * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters 
+       when getting log attrs. Get a slice, so that pixmaps and stuff
+       are properly handled.
+
+       * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you
+       paste into the selection (replaces selection now, previously
+       crashed or added to selection). Reveals longstanding btree bug -
+       select multiple lines, middle-click on the selection, boom. This
+       isn't related to my changes though.
+
+       * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect
+       PangoLogAttrs changes
+       (gtk_entry_move_backward_word): ditto
+
+        * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion
+       functions return bool whether the iter moved onto a
+       dereferenceable position.
+       * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public
+       functions for motion in terms of display lines.
+
+       * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to
+       get the buffer a mark is inside
+       
+2000-12-01  Alexander Larsson  <alexl@redhat.com>
 
        * gdk/linux-fb/Makefile.am:
        * modules/linux-fb/Makefile.am:
index 6f525e615236608b1fad29102288bf4185a6c7da..49b9f5c17a874f58b7e1a508e252b77b0c10e61d 100644 (file)
@@ -1,4 +1,40 @@
-2000-12-01    <alexl@redhat.com>
+2000-11-30  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create
+       dangling pointers to the appearance attributes from the 
+       line display
+
+       * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative
+       width/height to mean "full width/height of drawable"
+
+       * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple
+       click to select word/line
+       
+       * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters 
+       when getting log attrs. Get a slice, so that pixmaps and stuff
+       are properly handled.
+
+       * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you
+       paste into the selection (replaces selection now, previously
+       crashed or added to selection). Reveals longstanding btree bug -
+       select multiple lines, middle-click on the selection, boom. This
+       isn't related to my changes though.
+
+       * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect
+       PangoLogAttrs changes
+       (gtk_entry_move_backward_word): ditto
+
+        * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion
+       functions return bool whether the iter moved onto a
+       dereferenceable position.
+       * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public
+       functions for motion in terms of display lines.
+
+       * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to
+       get the buffer a mark is inside
+       
+2000-12-01  Alexander Larsson  <alexl@redhat.com>
 
        * gdk/linux-fb/Makefile.am:
        * modules/linux-fb/Makefile.am:
index 6f525e615236608b1fad29102288bf4185a6c7da..49b9f5c17a874f58b7e1a508e252b77b0c10e61d 100644 (file)
@@ -1,4 +1,40 @@
-2000-12-01    <alexl@redhat.com>
+2000-11-30  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create
+       dangling pointers to the appearance attributes from the 
+       line display
+
+       * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative
+       width/height to mean "full width/height of drawable"
+
+       * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple
+       click to select word/line
+       
+       * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters 
+       when getting log attrs. Get a slice, so that pixmaps and stuff
+       are properly handled.
+
+       * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you
+       paste into the selection (replaces selection now, previously
+       crashed or added to selection). Reveals longstanding btree bug -
+       select multiple lines, middle-click on the selection, boom. This
+       isn't related to my changes though.
+
+       * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect
+       PangoLogAttrs changes
+       (gtk_entry_move_backward_word): ditto
+
+        * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion
+       functions return bool whether the iter moved onto a
+       dereferenceable position.
+       * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public
+       functions for motion in terms of display lines.
+
+       * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to
+       get the buffer a mark is inside
+       
+2000-12-01  Alexander Larsson  <alexl@redhat.com>
 
        * gdk/linux-fb/Makefile.am:
        * modules/linux-fb/Makefile.am:
index 6f525e615236608b1fad29102288bf4185a6c7da..49b9f5c17a874f58b7e1a508e252b77b0c10e61d 100644 (file)
@@ -1,4 +1,40 @@
-2000-12-01    <alexl@redhat.com>
+2000-11-30  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create
+       dangling pointers to the appearance attributes from the 
+       line display
+
+       * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative
+       width/height to mean "full width/height of drawable"
+
+       * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple
+       click to select word/line
+       
+       * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters 
+       when getting log attrs. Get a slice, so that pixmaps and stuff
+       are properly handled.
+
+       * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you
+       paste into the selection (replaces selection now, previously
+       crashed or added to selection). Reveals longstanding btree bug -
+       select multiple lines, middle-click on the selection, boom. This
+       isn't related to my changes though.
+
+       * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect
+       PangoLogAttrs changes
+       (gtk_entry_move_backward_word): ditto
+
+        * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion
+       functions return bool whether the iter moved onto a
+       dereferenceable position.
+       * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public
+       functions for motion in terms of display lines.
+
+       * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to
+       get the buffer a mark is inside
+       
+2000-12-01  Alexander Larsson  <alexl@redhat.com>
 
        * gdk/linux-fb/Makefile.am:
        * modules/linux-fb/Makefile.am:
index facc185e9cfaf521f45a6261c07155d466030d3f..fcab539e584cf3173ed464950e20461c996be9b0 100644 (file)
@@ -486,9 +486,12 @@ gdk_drawable_get_image (GdkDrawable *drawable,
   g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
   g_return_val_if_fail (x >= 0, NULL);
   g_return_val_if_fail (y >= 0, NULL);
-  g_return_val_if_fail (width >= 0, NULL);
-  g_return_val_if_fail (height >= 0, NULL);
 
+  if (width < 0 || height < 0)
+    gdk_drawable_get_size (drawable,
+                           width < 0 ? &width : NULL,
+                           height < 0 ? &height : NULL);
+  
   composite =
     GDK_DRAWABLE_GET_CLASS (drawable)->get_composite_drawable (drawable,
                                                                x, y,
index 865f261b9a7715db2fdc3b770470c5202f1b6e7f..45c7f05927056130c54711956a74be2e1cbc5dbf 100644 (file)
@@ -2111,20 +2111,12 @@ gtk_entry_move_forward_word (GtkEntry *entry,
       gint n_attrs;
 
       pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
-
-      /* Advance over white space */
-      while (new_pos < n_attrs && log_attrs[new_pos].is_white)
-       new_pos++;
       
-      /* Find the next word beginning */
+      /* Find the next word end */
       new_pos++;
-      while (new_pos < n_attrs && !log_attrs[new_pos].is_word_stop)
+      while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
        new_pos++;
 
-      /* Back up over white space */
-      while (new_pos > 0 && log_attrs[new_pos - 1].is_white)
-       new_pos--;
-
       g_free (log_attrs);
       g_object_unref (G_OBJECT (layout));
     }
@@ -2155,7 +2147,7 @@ gtk_entry_move_backward_word (GtkEntry *entry,
       new_pos = start - 1;
 
       /* Find the previous word beginning */
-      while (new_pos > 0 && !log_attrs[new_pos].is_word_stop)
+      while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
        new_pos--;
 
       g_free (log_attrs);
index 9cd8dbba9f78387f58cd787cc08940f8e2d2d3a6..db770bab666f1bb000ea5a6c53415bcc1f0221b8 100644 (file)
@@ -2172,24 +2172,40 @@ pre_paste_prep (ClipboardRequest *request_data,
                 GtkTextIter      *insert_point)
 {
   GtkTextBuffer *buffer = request_data->buffer;
+  
+  get_paste_point (buffer, insert_point, TRUE);
 
+  /* If we're going to replace the selection, we insert before it to
+   * avoid messing it up, then we delete the selection after inserting.
+   */
   if (request_data->replace_selection)
     {
       GtkTextIter start, end;
       
       if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
+        *insert_point = start;
+    }
+}
+
+static void
+post_paste_cleanup (ClipboardRequest *request_data)
+{
+  if (request_data->replace_selection)
+    {
+      GtkTextIter start, end;
+      
+      if (gtk_text_buffer_get_selection_bounds (request_data->buffer,
+                                                &start, &end))
         {
           if (request_data->interactive)
-            gtk_text_buffer_delete_interactive (buffer,
+            gtk_text_buffer_delete_interactive (request_data->buffer,
                                                 &start,
                                                 &end,
                                                 request_data->default_editable);
           else
-            gtk_text_buffer_delete (buffer, &start, &end);
+            gtk_text_buffer_delete (request_data->buffer, &start, &end);
         }
     }
-      
-  get_paste_point (buffer, insert_point, TRUE);
 }
 
 /* Called when we request a paste and receive the text data
@@ -2214,6 +2230,8 @@ clipboard_text_received (GtkClipboard *clipboard,
       else
         gtk_text_buffer_insert (buffer, &insert_point,
                                 str, -1);
+
+      post_paste_cleanup (request_data);
     }
 
   g_object_unref (G_OBJECT (buffer));
@@ -2253,6 +2271,33 @@ selection_data_get_buffer (GtkSelectionData *selection_data,
   return src_buffer;
 }
 
+#if 0
+/* These are pretty handy functions; maybe something like them
+ * should be in the public API. Also, there are other places in this
+ * file where they could be used.
+ */
+static gpointer
+save_iter (const GtkTextIter *iter,
+           gboolean           left_gravity)
+{
+  return gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (iter),
+                                      NULL,
+                                      iter,
+                                      TRUE);
+}
+
+static void
+restore_iter (const GtkTextIter *iter,
+              gpointer           save_id)
+{
+  gtk_text_buffer_get_iter_at_mark (gtk_text_mark_get_buffer (save_id),
+                                    (GtkTextIter*) iter,
+                                    save_id);
+  gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (save_id),
+                               save_id);
+}
+#endif
+
 static void
 paste_from_buffer (ClipboardRequest    *request_data,
                    GtkTextBuffer       *src_buffer,
@@ -2274,6 +2319,8 @@ paste_from_buffer (ClipboardRequest    *request_data,
                                          end,
                                          request_data->interactive);
     }
+
+  post_paste_cleanup (request_data);
       
   g_object_unref (G_OBJECT (src_buffer));
 }
@@ -2392,13 +2439,14 @@ paste (GtkTextBuffer *buffer,
    * replace the selection with the new text, otherwise, you
    * simply insert the new text at the point where the click
    * occured, unselecting any selected text. The replace_selection
-   * flag toggles this behavior. FIXME set the flag based on something.
+   * flag toggles this behavior.
    */
   data->replace_selection = FALSE;
   
   get_paste_point (buffer, &paste_point, FALSE);
   if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end) &&
-      gtk_text_iter_in_range (&paste_point, &start, &end))
+      (gtk_text_iter_in_range (&paste_point, &start, &end) ||
+       gtk_text_iter_equal (&paste_point, &end)))
     data->replace_selection = TRUE;
 
   if (is_clipboard)
index e5a6d3b7211d89fbb911460c600f79b2cda987d0..b02ade89f470a6f070ddf87f4fd1bb5009c20269 100644 (file)
@@ -796,7 +796,9 @@ gtk_text_layout_draw (GtkTextLayout *layout,
 
       current_y += line_display->height;
       gtk_text_layout_free_line_display (layout, line_display);
-
+      render_state->last_appearance = NULL;
+      render_state->last_bg_appearance = NULL;
+      
       tmp_list = g_slist_next (tmp_list);
     }
 
index 1d90ceb433b9b969616d410bf6a0715f6467de12..d73e0a8589d1af86c58b17b8cb70fc7e6cb6e6c8 100644 (file)
@@ -2368,14 +2368,9 @@ find_word_end_func (PangoLogAttr *attrs,
 {
   ++offset; /* We always go to the NEXT word end */
 
-  /* Find start of next word */
+  /* Find end of next word */
   while (offset < min_offset + len &&
-         !attrs[offset].is_word_stop)
-    ++offset;
-
-  /* Find end */
-  while (offset < min_offset + len &&
-         !attrs[offset].is_white)
+         !attrs[offset].is_word_end)
     ++offset;
 
   *found_offset = offset;
@@ -2383,6 +2378,16 @@ find_word_end_func (PangoLogAttr *attrs,
   return offset < min_offset + len;
 }
 
+static gboolean
+is_word_end_func (PangoLogAttr *attrs,
+                  gint          offset,
+                  gint          min_offset,
+                  gint          len,
+                  gint         *found_offset)
+{
+  return attrs[offset].is_word_end;
+}
+
 static gboolean
 find_word_start_func (PangoLogAttr *attrs,
                       gint          offset,
@@ -2392,14 +2397,9 @@ find_word_start_func (PangoLogAttr *attrs,
 {
   --offset; /* We always go to the NEXT word start */
 
-  /* Find end of prev word */
+  /* Find start of prev word */
   while (offset >= min_offset &&
-         attrs[offset].is_white)
-    --offset;
-
-  /* Find start */
-  while (offset >= min_offset &&
-         !attrs[offset].is_word_stop)
+         !attrs[offset].is_word_start)
     --offset;
 
   *found_offset = offset;
@@ -2407,31 +2407,53 @@ find_word_start_func (PangoLogAttr *attrs,
   return offset >= min_offset;
 }
 
-/* FIXME this function is very, very gratuitously slow */
 static gboolean
-find_by_log_attrs (GtkTextIter *iter,
-                   FindLogAttrFunc func,
-                   gboolean forward)
+is_word_start_func (PangoLogAttr *attrs,
+                    gint          offset,
+                    gint          min_offset,
+                    gint          len,
+                    gint         *found_offset)
+{
+  return attrs[offset].is_word_start;
+}
+
+static gboolean
+inside_word_func (PangoLogAttr *attrs,
+                  gint          offset,
+                  gint          min_offset,
+                  gint          len,
+                  gint         *found_offset)
+{
+  /* Find next word start or end */
+  while (offset >= min_offset &&
+         !(attrs[offset].is_word_start || attrs[offset].is_word_end))
+    --offset;
+
+  return attrs[offset].is_word_start;
+}
+
+static gboolean
+test_log_attrs (GtkTextIter       *iter,
+                FindLogAttrFunc    func,
+                gint              *found_offset)
 {
-  GtkTextIter orig;
   GtkTextIter start;
   GtkTextIter end;
   gchar *paragraph;
   gint char_len, byte_len;
   PangoLogAttr *attrs;
   int offset;
-  gboolean found = FALSE;
+  gboolean result = FALSE;
 
   g_return_val_if_fail (iter != NULL, FALSE);
 
-  orig = *iter;
   start = *iter;
   end = *iter;
 
   gtk_text_iter_set_line_offset (&start, 0);
-  gtk_text_iter_forward_to_newline (&end);
+  gtk_text_iter_forward_line (&end);
 
-  paragraph = gtk_text_iter_get_text (&start, &end);
+  paragraph = gtk_text_iter_get_slice (&start, &end);
   char_len = g_utf8_strlen (paragraph, -1);
   byte_len = strlen (paragraph);
 
@@ -2451,13 +2473,32 @@ find_by_log_attrs (GtkTextIter *iter,
 
       g_free (lang);
 
-      found = (* func) (attrs, offset, 0, char_len, &offset);
+      result = (* func) (attrs, offset, 0, char_len, found_offset);
 
       g_free (attrs);
     }
 
   g_free (paragraph);
 
+  return result;
+}
+
+/* FIXME this function is very, very gratuitously slow */
+static gboolean
+find_by_log_attrs (GtkTextIter    *iter,
+                   FindLogAttrFunc func,
+                   gboolean        forward)
+{
+  GtkTextIter orig;
+  gint offset = 0;
+  gboolean found = FALSE;
+
+  g_return_val_if_fail (iter != NULL, FALSE);
+
+  orig = *iter;
+
+  found = test_log_attrs (iter, func, &offset);
+  
   if (!found)
     {
       if (forward)
@@ -2502,7 +2543,7 @@ gtk_text_iter_backward_word_start (GtkTextIter      *iter)
  */
 gboolean
 gtk_text_iter_forward_word_ends (GtkTextIter      *iter,
-                                 gint               count)
+                                 gint              count)
 {
   g_return_val_if_fail (iter != NULL, FALSE);
   g_return_val_if_fail (count > 0, FALSE);
@@ -2540,6 +2581,25 @@ gtk_text_iter_backward_word_starts (GtkTextIter      *iter,
   return TRUE;
 }
 
+
+gboolean
+gtk_text_iter_starts_word (const GtkTextIter *iter)
+{
+  return test_log_attrs (iter, is_word_start_func, NULL);
+}
+
+gboolean
+gtk_text_iter_ends_word (const GtkTextIter *iter)
+{
+  return test_log_attrs (iter, is_word_end_func, NULL);
+}
+
+gboolean
+gtk_text_iter_inside_word (const GtkTextIter *iter)
+{
+  return test_log_attrs (iter, inside_word_func, NULL);
+}
+
 void
 gtk_text_iter_set_line_offset (GtkTextIter *iter,
                                gint char_on_line)
index caadecb2a272c920284845ba864a1ef157cfdc76..1c32fdaeb0650eb2993d4c665bfce2dce29004d7 100644 (file)
@@ -124,6 +124,9 @@ GSList  *gtk_text_iter_get_tags          (const GtkTextIter   *iter);
 gboolean gtk_text_iter_editable          (const GtkTextIter   *iter,
                                           gboolean             default_setting);
 
+gboolean gtk_text_iter_starts_word       (const GtkTextIter   *iter);
+gboolean gtk_text_iter_ends_word         (const GtkTextIter   *iter);
+gboolean gtk_text_iter_inside_word       (const GtkTextIter   *iter);
 gboolean gtk_text_iter_starts_line       (const GtkTextIter   *iter);
 gboolean gtk_text_iter_ends_line         (const GtkTextIter   *iter);
 
index c43320e50583ef6a2c91be702cdb7df3418c5783..877eadc3e97ca78b03458ec7c1f5338da21e8f26 100644 (file)
@@ -2209,7 +2209,6 @@ find_display_line_below (GtkTextLayout *layout,
   while (line && !found_line)
     {
       GtkTextLineDisplay *display = gtk_text_layout_get_line_display (layout, line, FALSE);
-      gint byte_index = 0;
       PangoLayoutIter *layout_iter;
 
       layout_iter = pango_layout_get_iter (display->layout);
@@ -2221,7 +2220,7 @@ find_display_line_below (GtkTextLayout *layout,
           gint first_y, last_y;
           PangoLayoutLine *layout_line = pango_layout_iter_get_line (layout_iter);
 
-          found_byte = byte_index;
+          found_byte = layout_line->start_index;
           
           if (line_top >= y)
             {
@@ -2231,8 +2230,6 @@ find_display_line_below (GtkTextLayout *layout,
 
           pango_layout_iter_get_line_yrange (layout_iter, &first_y, &last_y);
           line_top += (last_y - first_y) / PANGO_SCALE;
-
-          byte_index += layout_line->length;
         }
       while (pango_layout_iter_next_line (layout_iter));
 
@@ -2278,8 +2275,6 @@ find_display_line_above (GtkTextLayout *layout,
     {
       GtkTextLineDisplay *display = gtk_text_layout_get_line_display (layout, line, FALSE);
       PangoRectangle logical_rect;
-
-      gint byte_index = 0;
       PangoLayoutIter *layout_iter;
       gint tmp_top;
 
@@ -2296,7 +2291,7 @@ find_display_line_above (GtkTextLayout *layout,
           gint first_y, last_y;
           PangoLayoutLine *layout_line = pango_layout_iter_get_line (layout_iter);
 
-          found_byte = byte_index;
+          found_byte = layout_line->start_index;
 
           pango_layout_iter_get_line_yrange (layout_iter, &first_y, &last_y);
           
@@ -2305,11 +2300,8 @@ find_display_line_above (GtkTextLayout *layout,
           if (tmp_top < y)
             {
               found_line = line;
-              found_byte = byte_index;
               goto done;
             }
-
-          byte_index += layout_line->length;
         }
       while (pango_layout_iter_next_line (layout_iter));
 
@@ -2383,7 +2375,7 @@ gtk_text_layout_clamp_iter_to_vrange (GtkTextLayout *layout,
  * Move the iterator to the beginning of the previous line. The lines
  * of a wrapped paragraph are treated as distinct for this operation.
  **/
-void
+gboolean
 gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout,
                                             GtkTextIter   *iter)
 {
@@ -2392,11 +2384,14 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout,
   gint line_byte;
   GSList *tmp_list;
   PangoLayoutLine *layout_line;
+  GtkTextIter orig;
+  
+  g_return_val_if_fail (layout != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
 
-  g_return_if_fail (layout != NULL);
-  g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
-  g_return_if_fail (iter != NULL);
-
+  orig = *iter;
+  
   line = gtk_text_iter_get_text_line (iter);
   display = gtk_text_layout_get_line_display (layout, line, FALSE);
   line_byte = line_display_iter_to_index (layout, display, iter);
@@ -2410,49 +2405,49 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout,
 
       if (prev_line)
         {
-          gint byte_offset = 0;
-
           gtk_text_layout_free_line_display (layout, display);
           display = gtk_text_layout_get_line_display (layout, prev_line, FALSE);
 
-         tmp_list = pango_layout_get_lines (display->layout);
-
+          tmp_list = pango_layout_get_lines (display->layout);
+          
           while (tmp_list->next)
             {
               layout_line = tmp_list->data;
               tmp_list = tmp_list->next;
-
-              byte_offset += layout_line->length;
             }
 
-         line_display_index_to_iter (layout, display, iter, byte_offset, 0);
+          line_display_index_to_iter (layout, display, iter,
+                                      layout_line->start_index + layout_line->length, 0);
         }
       else
        line_display_index_to_iter (layout, display, iter, 0, 0);
     }
   else
     {
-      gint prev_offset = 0;
-      gint byte_offset = layout_line->length;
+      gint prev_offset = layout_line->start_index;
 
       tmp_list = tmp_list->next;
       while (tmp_list)
         {
           layout_line = tmp_list->data;
 
-          if (line_byte < byte_offset + layout_line->length || !tmp_list->next)
+          if (line_byte < layout_line->start_index + layout_line->length ||
+              !tmp_list->next)
             {
              line_display_index_to_iter (layout, display, iter, prev_offset, 0);
               break;
             }
 
-          prev_offset = byte_offset;
-          byte_offset += layout_line->length;
+          prev_offset = layout_line->start_index;
           tmp_list = tmp_list->next;
         }
     }
 
   gtk_text_layout_free_line_display (layout, display);
+
+  return
+    !gtk_text_iter_equal (iter, &orig) &&
+    !gtk_text_iter_is_last (iter);
 }
 
 /**
@@ -2464,27 +2459,28 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout,
  * lines of a wrapped paragraph are treated as distinct for
  * this operation.
  **/
-void
+gboolean
 gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout,
                                         GtkTextIter   *iter)
 {
   GtkTextLine *line;
   GtkTextLineDisplay *display;
   gint line_byte;
-
+  GtkTextIter orig;
   gboolean found = FALSE;
   gboolean found_after = FALSE;
   gboolean first = TRUE;
 
-  g_return_if_fail (layout != NULL);
-  g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
-  g_return_if_fail (iter != NULL);
+  g_return_val_if_fail (layout != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
 
+  orig = *iter;
+  
   line = gtk_text_iter_get_text_line (iter);
 
   while (line && !found_after)
     {
-      gint byte_offset = 0;
       GSList *tmp_list;
 
       display = gtk_text_layout_get_line_display (layout, line, FALSE);
@@ -2504,13 +2500,13 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout,
 
           if (found)
             {
-             line_display_index_to_iter (layout, display, iter, byte_offset, 0);
+             line_display_index_to_iter (layout, display, iter,
+                                          layout_line->start_index, 0);
               found_after = TRUE;
             }
-          else if (line_byte < byte_offset + layout_line->length || !tmp_list->next)
+          else if (line_byte < layout_line->start_index + layout_line->length || !tmp_list->next)
             found = TRUE;
-
-          byte_offset += layout_line->length;
+          
           tmp_list = tmp_list->next;
         }
 
@@ -2518,6 +2514,10 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout,
 
       line = gtk_text_line_next (line);
     }
+
+  return
+    !gtk_text_iter_equal (iter, &orig) &&
+    !gtk_text_iter_is_last (iter);
 }
 
 /**
@@ -2528,7 +2528,7 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout,
  *
  * Move to the beginning or end of a display line.
  **/
-void
+gboolean
 gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout,
                                        GtkTextIter   *iter,
                                        gint           direction)
@@ -2536,13 +2536,15 @@ gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout,
   GtkTextLine *line;
   GtkTextLineDisplay *display;
   gint line_byte;
-  gint byte_offset = 0;
   GSList *tmp_list;
+  GtkTextIter orig;
+  
+  g_return_val_if_fail (layout != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
 
-  g_return_if_fail (layout != NULL);
-  g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
-  g_return_if_fail (iter != NULL);
-
+  orig = *iter;
+  
   line = gtk_text_iter_get_text_line (iter);
   display = gtk_text_layout_get_line_display (layout, line, FALSE);
   line_byte = line_display_iter_to_index (layout, display, iter);
@@ -2552,10 +2554,10 @@ gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout,
     {
       PangoLayoutLine *layout_line = tmp_list->data;
 
-      if (line_byte < byte_offset + layout_line->length || !tmp_list->next)
+      if (line_byte < layout_line->start_index + layout_line->length || !tmp_list->next)
         {
          line_display_index_to_iter (layout, display, iter,
-                                     direction < 0 ? byte_offset : byte_offset + layout_line->length,
+                                     direction < 0 ? layout_line->start_index : layout_line->start_index + layout_line->length,
                                      0);
 
           /* FIXME: As a bad hack, we move back one position when we
@@ -2567,12 +2569,66 @@ gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout,
 
           break;
         }
-
-      byte_offset += layout_line->length;
+      
       tmp_list = tmp_list->next;
     }
 
   gtk_text_layout_free_line_display (layout, display);
+
+  return
+    !gtk_text_iter_equal (iter, &orig) &&
+    !gtk_text_iter_is_last (iter);
+}
+
+
+/**
+ * gtk_text_layout_iter_starts_line:
+ * @layout: a #GtkTextLayout
+ * @iter: iterator to test
+ *
+ * Tests whether an iterator is at the start of a display line.
+ **/
+gboolean
+gtk_text_layout_iter_starts_line (GtkTextLayout       *layout,
+                                  const GtkTextIter   *iter)
+{
+  GtkTextLine *line;
+  GtkTextLineDisplay *display;
+  gint line_byte;
+  GSList *tmp_list;
+  
+  g_return_val_if_fail (layout != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
+
+  line = gtk_text_iter_get_text_line (iter);
+  display = gtk_text_layout_get_line_display (layout, line, FALSE);
+  line_byte = line_display_iter_to_index (layout, display, iter);
+
+  tmp_list = pango_layout_get_lines (display->layout);
+  while (tmp_list)
+    {
+      PangoLayoutLine *layout_line = tmp_list->data;
+
+      if (line_byte < layout_line->start_index + layout_line->length ||
+          !tmp_list->next)
+        {
+          /* We're located on this line of the para delimiters before
+           * it
+           */
+          gtk_text_layout_free_line_display (layout, display);
+          
+          if (line_byte == layout_line->start_index)
+            return TRUE;
+          else
+            return FALSE;
+        }
+      
+      tmp_list = tmp_list->next;
+    }
+
+  g_assert_not_reached ();
+  return FALSE;
 }
 
 /**
@@ -2593,7 +2649,6 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout,
   GtkTextLine *line;
   GtkTextLineDisplay *display;
   gint line_byte;
-  gint byte_offset = 0;
   PangoLayoutIter *layout_iter;
   
   g_return_if_fail (layout != NULL);
@@ -2611,7 +2666,7 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout,
     {
       PangoLayoutLine *layout_line = pango_layout_iter_get_line (layout_iter);
 
-      if (line_byte < byte_offset + layout_line->length ||
+      if (line_byte < layout_line->start_index + layout_line->length ||
           pango_layout_iter_at_last_line (layout_iter))
         {
           PangoRectangle logical_rect;
@@ -2628,8 +2683,6 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout,
 
           break;
         }
-
-      byte_offset += layout_line->length;
     }
   while (pango_layout_iter_next_line (layout_iter));
 
@@ -2657,16 +2710,19 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout,
  * is moved off of the end of a run.
  **/
 
-void
+gboolean
 gtk_text_layout_move_iter_visually (GtkTextLayout *layout,
                                     GtkTextIter   *iter,
                                     gint           count)
 {
   GtkTextLineDisplay *display = NULL;
+  GtkTextIter orig;
+  
+  g_return_val_if_fail (layout != NULL, FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
 
-  g_return_if_fail (layout != NULL);
-  g_return_if_fail (iter != NULL);
-
+  orig = *iter;
+  
   while (count != 0)
     {
       GtkTextLine *line = gtk_text_iter_get_text_line (iter);
@@ -2715,8 +2771,8 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout,
           line = gtk_text_line_previous (line);
 
           if (!line)
-            return;
-
+            goto done;
+          
          gtk_text_layout_free_line_display (layout, display);
          display = gtk_text_layout_get_line_display (layout, line, FALSE);
           new_index = gtk_text_line_byte_count (line);
@@ -2725,7 +2781,7 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout,
         {
           line = gtk_text_line_next (line);
           if (!line)
-            return;
+            goto done;
 
          gtk_text_layout_free_line_display (layout, display);
          display = gtk_text_layout_get_line_display (layout, line, FALSE);
@@ -2738,6 +2794,12 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout,
     }
 
   gtk_text_layout_free_line_display (layout, display);
+
+ done:
+  
+  return
+    !gtk_text_iter_equal (iter, &orig) &&
+    !gtk_text_iter_is_last (iter);
 }
 
 void
index 81e8824f012d2279dfc33bd22873ee04e44843b0..8977a97eb71d7ed34d51660283801f3e2eb1f220 100644 (file)
@@ -339,20 +339,22 @@ gboolean gtk_text_layout_clamp_iter_to_vrange (GtkTextLayout     *layout,
                                                gint               top,
                                                gint               bottom);
 
-void gtk_text_layout_move_iter_to_line_end      (GtkTextLayout *layout,
-                                                 GtkTextIter   *iter,
-                                                 gint           direction);
-void gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout,
-                                                 GtkTextIter   *iter);
-void gtk_text_layout_move_iter_to_next_line     (GtkTextLayout *layout,
-                                                 GtkTextIter   *iter);
-void gtk_text_layout_move_iter_to_x             (GtkTextLayout *layout,
-                                                 GtkTextIter   *iter,
-                                                 gint           x);
-void gtk_text_layout_move_iter_visually         (GtkTextLayout *layout,
-                                                 GtkTextIter   *iter,
-                                                 gint           count);
-
+gboolean gtk_text_layout_move_iter_to_line_end      (GtkTextLayout *layout,
+                                                     GtkTextIter   *iter,
+                                                     gint           direction);
+gboolean gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout,
+                                                     GtkTextIter   *iter);
+gboolean gtk_text_layout_move_iter_to_next_line     (GtkTextLayout *layout,
+                                                     GtkTextIter   *iter);
+void     gtk_text_layout_move_iter_to_x             (GtkTextLayout *layout,
+                                                     GtkTextIter   *iter,
+                                                     gint           x);
+gboolean gtk_text_layout_move_iter_visually         (GtkTextLayout *layout,
+                                                     GtkTextIter   *iter,
+                                                     gint           count);
+
+gboolean gtk_text_layout_iter_starts_line           (GtkTextLayout       *layout,
+                                                     const GtkTextIter   *iter);
 
 /* Don't use these. Use gtk_text_view_add_child_at_anchor().
  * These functions are defined in gtktextchild.c, but here
index 4e20eb300c6a4898f26fd60ad352a502155c6cd5..e18ea3295ea74ff8b29801a8d633f62a266273fc 100644 (file)
@@ -179,7 +179,7 @@ gtk_text_mark_get_deleted (GtkTextMark *mark)
 {
   GtkTextLineSegment *seg;
 
-  g_return_val_if_fail (mark != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_TEXT_MARK (mark), FALSE);
 
   seg = mark->segment;
 
@@ -189,6 +189,30 @@ gtk_text_mark_get_deleted (GtkTextMark *mark)
   return seg->body.mark.tree == NULL;
 }
 
+/**
+ * gtk_text_mark_get_buffer:
+ * @mark: a #GtkTextMark
+ * 
+ * Gets the buffer this mark is located inside,
+ * or NULL if the mark is deleted.
+ * 
+ * Return value: the mark's #GtkTextBuffer
+ **/
+GtkTextBuffer*
+gtk_text_mark_get_buffer (GtkTextMark *mark)
+{
+  GtkTextLineSegment *seg;
+
+  g_return_val_if_fail (GTK_IS_TEXT_MARK (mark), FALSE);
+
+  seg = mark->segment;
+
+  if (seg->body.mark.tree == NULL)
+    return NULL;
+  else
+    return gtk_text_btree_get_buffer (seg->body.mark.tree);
+}
+
 /*
  * Macro that determines the size of a mark segment:
  */
index e2130c5acdd0cdcf5caed00d352138dfefda1f78..3b2d0fc9aa43c414d9ffb313ce518fb964f89ab5 100644 (file)
@@ -81,12 +81,14 @@ struct _GtkTextMarkClass
 
 GType        gtk_text_mark_get_type   (void) G_GNUC_CONST;
 
-void         gtk_text_mark_set_visible (GtkTextMark *mark,
-                                        gboolean     setting);
-gboolean     gtk_text_mark_get_visible (GtkTextMark *mark);
+void           gtk_text_mark_set_visible (GtkTextMark *mark,
+                                          gboolean     setting);
+gboolean       gtk_text_mark_get_visible (GtkTextMark *mark);
+
 /* FIXME gconst */
-const char  *gtk_text_mark_get_name    (GtkTextMark *mark);
-gboolean     gtk_text_mark_get_deleted (GtkTextMark *mark);
+const char  *  gtk_text_mark_get_name    (GtkTextMark *mark);
+gboolean       gtk_text_mark_get_deleted (GtkTextMark *mark);
+GtkTextBuffer* gtk_text_mark_get_buffer  (GtkTextMark *mark);
 
 
 #ifdef __cplusplus
index 489a04e0378fcbc5f6185074fb5f6ef38f71e2d7..78ac46a6aae4f109cb15bc3777ff5c9f142b1233 100644 (file)
@@ -2637,7 +2637,69 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
          gtk_text_view_popup_menu (text_view, event);
         }
     }
+  else if ((event->type == GDK_2BUTTON_PRESS ||
+            event->type == GDK_3BUTTON_PRESS) &&
+           event->button == 1)
+    {
+      GtkTextIter start, end;
+
+      /* End the selection drag, otherwise we'd clear the new
+       * word/line selection on button release
+       */
+      gtk_text_view_end_selection_drag (text_view, event);
+
+      gtk_text_layout_get_iter_at_pixel (text_view->layout,
+                                         &start,
+                                         event->x + text_view->xoffset,
+                                         event->y + text_view->yoffset); 
 
+      end = start;
+      
+      if (event->type == GDK_2BUTTON_PRESS)
+        {
+          if (gtk_text_iter_inside_word (&start))
+            {
+              if (!gtk_text_iter_starts_word (&start))
+                gtk_text_iter_backward_word_start (&start);
+              
+              if (!gtk_text_iter_ends_word (&end))
+                gtk_text_iter_forward_word_end (&end);
+            }
+        }
+      else if (event->type == GDK_3BUTTON_PRESS)
+        {
+          if (gtk_text_view_starts_display_line (text_view, &start))
+            {
+              /* If on a display line boundary, we assume the user
+               * clicked off the end of a line and we therefore select
+               * the line before the boundary.
+               */
+              gtk_text_view_backward_display_line_start (text_view, &start);
+            }
+          else
+            {
+              /* start isn't on the start of a line, so we move it to the
+               * start, and move end to the end unless it's already there.
+               */
+              gtk_text_view_backward_display_line_start (text_view, &start);
+
+              if (!gtk_text_view_starts_display_line (text_view, &end))
+                gtk_text_view_forward_display_line_end (text_view, &end);
+            }
+        }
+
+      gtk_text_buffer_move_mark (get_buffer (text_view),
+                                 gtk_text_buffer_get_selection_bound (get_buffer (text_view)),
+                                 &start);
+      gtk_text_buffer_move_mark (get_buffer (text_view),
+                                 gtk_text_buffer_get_insert (get_buffer (text_view)),
+                                 &end);
+
+      text_view->just_selected_element = TRUE;
+      
+      return TRUE;
+    }
+  
   return FALSE;
 }
 
@@ -2661,6 +2723,11 @@ gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
 
       if (gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget), event))
         return TRUE;
+      else if (text_view->just_selected_element)
+        {
+          text_view->just_selected_element = FALSE;
+          return FALSE;
+        }
       else
         {
           /* Unselect everything; probably we were dragging, or clicked
@@ -5457,3 +5524,80 @@ gtk_text_view_move_child          (GtkTextView          *text_view,
 }
 
 
+
+/* Iterator operations */
+
+gboolean
+gtk_text_view_forward_display_line (GtkTextView *text_view,
+                                    GtkTextIter *iter)
+{
+  g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
+
+  gtk_text_view_ensure_layout (text_view);
+
+  return gtk_text_layout_move_iter_to_next_line (text_view->layout, iter);
+}
+
+gboolean
+gtk_text_view_backward_display_line (GtkTextView *text_view,
+                                     GtkTextIter *iter)
+{
+  g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
+
+  gtk_text_view_ensure_layout (text_view);
+
+  return gtk_text_layout_move_iter_to_previous_line (text_view->layout, iter);
+}
+
+gboolean
+gtk_text_view_forward_display_line_end (GtkTextView *text_view,
+                                        GtkTextIter *iter)
+{
+  g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
+
+  gtk_text_view_ensure_layout (text_view);
+
+  return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, 1);
+}
+
+gboolean
+gtk_text_view_backward_display_line_start (GtkTextView *text_view,
+                                           GtkTextIter *iter)
+{
+  g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
+
+  gtk_text_view_ensure_layout (text_view);
+
+  return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, -1);
+}
+
+gboolean
+gtk_text_view_starts_display_line (GtkTextView       *text_view,
+                                   const GtkTextIter *iter)
+{
+  g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
+
+  gtk_text_view_ensure_layout (text_view);
+
+  return gtk_text_layout_iter_starts_line (text_view->layout, iter);
+}
+
+gboolean
+gtk_text_view_move_visually (GtkTextView *text_view,
+                             GtkTextIter *iter,
+                             gint         count)
+{
+  g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
+
+  gtk_text_view_ensure_layout (text_view);
+
+  return gtk_text_layout_move_iter_visually (text_view->layout, iter, count);
+}
+
+
index 880cff302eaea872075b10fdec27de4a9afb413b..edcc8f2870d4e7f1d5a3c56469143012642756a4 100644 (file)
@@ -87,7 +87,9 @@ struct _GtkTextView
   guint overwrite_mode : 1;
   guint cursor_visible : 1;
   guint  need_im_reset : 1;    /* If we have reset the IM since the last character entered */
-
+  /* just selected a word or line via double/triple click */
+  guint just_selected_element : 1;
+  
   GtkTextWindow *text_window;
   GtkTextWindow *left_window;
   GtkTextWindow *right_window;
@@ -226,6 +228,19 @@ void gtk_text_view_set_text_window_size   (GtkTextView       *text_view,
                                            gint               width,
                                            gint               height);
 
+gboolean gtk_text_view_forward_display_line           (GtkTextView       *text_view,
+                                                       GtkTextIter       *iter);
+gboolean gtk_text_view_backward_display_line          (GtkTextView       *text_view,
+                                                       GtkTextIter       *iter);
+gboolean gtk_text_view_forward_display_line_end       (GtkTextView       *text_view,
+                                                       GtkTextIter       *iter);
+gboolean gtk_text_view_backward_display_line_start    (GtkTextView       *text_view,
+                                                       GtkTextIter       *iter);
+gboolean gtk_text_view_starts_display_line            (GtkTextView       *text_view,
+                                                       const GtkTextIter *iter);
+gboolean gtk_text_view_move_visually                  (GtkTextView       *text_view,
+                                                       GtkTextIter       *iter,
+                                                       gint               count);
 
 /* Adding child widgets */
 void gtk_text_view_add_child_at_anchor (GtkTextView          *text_view,